package cn.blackhole.simple.domain.circuitBreaker.service.impl;

import cn.blackhole.simple.domain.circuitBreaker.model.objValue.CircuitState;
import cn.blackhole.simple.domain.circuitBreaker.service.CircuitBreaker;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

// 基础熔断器实现
public class DefaultCircuitBreaker implements CircuitBreaker {

    private final AtomicInteger failureCount = new AtomicInteger(0);

    private final AtomicInteger successCount = new AtomicInteger(0);

    private final AtomicReference<CircuitState> state = new AtomicReference<>(CircuitState.CLOSED);

    private final int failureThreshold;

    private final long resetTimeout;

    private final int halfOpenSuccessThreshold;

    private long lastStateChange;

    public DefaultCircuitBreaker(int failureThreshold, long resetTimeout, int halfOpenSuccessThreshold) {
        this.failureThreshold = failureThreshold;
        this.resetTimeout = resetTimeout;
        this.halfOpenSuccessThreshold = halfOpenSuccessThreshold;
    }

    @Override
    public boolean allowRequest() {
        if (state.get() == CircuitState.CLOSED) return true;

        if (state.get() == CircuitState.OPEN &&
                System.currentTimeMillis() - lastStateChange > resetTimeout) {
            state.compareAndSet(CircuitState.OPEN, CircuitState.HALF_OPEN);
            return true;
        }
        return state.get() == CircuitState.HALF_OPEN;
    }

    @Override
    public void recordSuccess() {
        if (state.get() == CircuitState.HALF_OPEN) {
            if (successCount.incrementAndGet() >= halfOpenSuccessThreshold) {
                reset();
            }
        } else {
            successCount.set(0);
            failureCount.set(0);
        }
    }

    @Override
    public void recordFailure() {
        if (failureCount.incrementAndGet() >= failureThreshold) {
            state.set(CircuitState.OPEN);
            lastStateChange = System.currentTimeMillis();
        }
    }

    @Override
    public CircuitState getState() {
        return null;
    }

    private void reset() {
        state.set(CircuitState.CLOSED);
        successCount.set(0);
        failureCount.set(0);
    }
}